﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Autofac;
using AutoMapper;
using Jinjia.Approve.Entity.Entity.JJFlow;
using Jinjia.Approve.IRepository;
using Jinjia.Approve.IRepository.JJFlow;
using Jinjia.Approve.IService.JJFlow;
using Jinjia.Approve.IService.JJFlow.Approvers;
using Jinjia.Approve.Model.Input.JJFlow;
using Jinjia.Approve.Model.VM.JJFlow;
using Jinjia.Approve.Model.VM.JJFlow.DTO;
using JinJia.Core.Base.Exceptions;
using Jinjia.Core.BaseInfrastructure.StorageModel.Model;
using Jinjia.Approve.Model.VM.JJFlow.Request;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Jinjia.Core.BaseInfrastructure.ApiResultCodeComponent;
using Jinjia.Approve.Common.Extensions;
using System.Net;
using Jinjia.Approve.IService;
using System.Linq.Expressions;
using Jinjia.Approve.Model.VM.Org;
using Jinjia.Approve.Service.JJFlow.Approvers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace Jinjia.Approve.Service.JJFlow
{
    public class JJFlowInstanceService : IJJFlowInstanceService
    {
        private readonly IFlowInstanceRepository _flowInstanceRepository;
        private readonly IFlowInstanceFormRepository _flowInstanceFormRepository;
        private readonly IFlowInstanceEmpRepository _flowInstanceEmpRepository;
        private readonly IFlowTemplateRepository _flowTemplateRepository;
        private readonly IFlowNodeRepository _flowNodeRepository;
        private readonly IFlowNodeEmpRepository _flowNodeEmpRepository;
        private readonly IErpaUserRoleRepository _erpaUserRoleRepository;
        private readonly IJJFlowNodeService _jjFlowNodeService;
        private readonly IJJFlowTemplateRemoteInterfaceService _jJFlowTemplateRemoteInterfaceService;
        private readonly IErpaUserRepository _erpaUserRepository;
        private readonly ApprovePlatformConfig _platformConfig = new ApprovePlatformConfig();
        private readonly IComponentContext _componentContext;
        private readonly IMapper _mapper;

        public JJFlowInstanceService(IFlowInstanceRepository flowInstanceRepository,
            IFlowInstanceFormRepository flowInstanceFormRepository,
            IFlowInstanceEmpRepository flowInstanceEmpRepository,
            IFlowTemplateRepository flowTemplateRepository,
            IFlowNodeRepository flowNodeRepository,
            IFlowNodeEmpRepository flowNodeEmpRepository,
            IErpaUserRoleRepository erpaUserRoleRepository,
            IComponentContext componentContext,
            IMapper mapper, IJJFlowNodeService jjFlowNodeService,
            IJJFlowTemplateRemoteInterfaceService jJFlowTemplateRemoteInterfaceService,
            IErpaUserRepository erpaUserRepository,
            IConfiguration configuration)
        {
            _flowInstanceRepository = flowInstanceRepository;
            _flowInstanceFormRepository = flowInstanceFormRepository;
            _flowInstanceEmpRepository = flowInstanceEmpRepository;
            _flowTemplateRepository = flowTemplateRepository;
            _flowNodeRepository = flowNodeRepository;
            _flowNodeEmpRepository = flowNodeEmpRepository;
            _erpaUserRoleRepository = erpaUserRoleRepository;
            _componentContext = componentContext;
            _mapper = mapper;
            _jjFlowNodeService = jjFlowNodeService;
            _jJFlowTemplateRemoteInterfaceService = jJFlowTemplateRemoteInterfaceService;
            _erpaUserRepository = erpaUserRepository;
            _platformConfig.ApprovePlatform = configuration.GetSection("ApprovePlatformConfig:ApprovePlatform").Value;
        }


        public async Task<JjFlowInstanceVM> GetById(int instance_id)
        {
            var jjFlowInstance = await _flowInstanceRepository.GetById(instance_id);
            if (jjFlowInstance != null)
            {
                return _mapper.Map<JjFlowInstanceVM>(jjFlowInstance);
            }

            return default;
        }

        public async Task<List<JjFlowInstanceVM>> IsExist(string modular_key, int template_id, string biz_order_id)
        {
            var jjFlowInstances = await _flowInstanceRepository.IsExist(modular_key, template_id, biz_order_id);
            var jjFlowInstanceVms = _mapper.Map<List<JjFlowInstanceVM>>(jjFlowInstances);
            return jjFlowInstanceVms;
        }

        public async Task<bool> CheckNodeUser(int node_id, int template_id, int user_id, int instance_id)
        {
            return await _flowInstanceEmpRepository.CheckNodeUser(node_id, template_id, user_id, instance_id);
        }

        public async Task<bool> CheckNodeTrack(int node_id, int user_id, int instance_id)
        {
            return await _flowInstanceEmpRepository.CheckNodeTrack(node_id, user_id, instance_id);
        }

        public async Task<JjFlowInstanceVM> GetInstanceInfo(string modular_key, string biz_order_id)
        {
            var jjFlowInstance = await _flowInstanceRepository.GetInstanceInfo(modular_key, biz_order_id);
            var jjFlowInstanceVm = _mapper.Map<JjFlowInstanceVM>(jjFlowInstance);
            return jjFlowInstanceVm;
        }

        public async Task<List<JjFlowInstanceVM>> GetInstanceListAsync(Expression<Func<jj_flow_instance, bool>> expression)
        {
            var jjFlowInstances = await _flowInstanceRepository.GetListAsync(expression);
            var jjFlowInstanceVms = _mapper.Map<List<JjFlowInstanceVM>>(jjFlowInstances);
            return jjFlowInstanceVms;
        }

        public async Task<int> Save(JjFlowInstanceVM data)
        {
            var jjFlowInstance = _mapper.Map<jj_flow_instance>(data);
            var id = await _flowInstanceRepository.Save(jjFlowInstance);
            return id;
        }

        public async Task SaveInstanceForm(int instance_id, Dictionary<string, string> dic, List<jj_flow_dictcode> dicCodeList)
        {
            var form_list = new List<jj_flow_instance_form>();

            foreach (var item in dic)
            {
                if (dicCodeList.Any(x => x.dictcode_key == item.Key) || item.Key == "dingding_depart_id")
                {
                    var form = new jj_flow_instance_form
                    {
                        instance_id = instance_id,
                        form_key = item.Key,
                        form_value = item.Value
                    };
                    form_list.Add(form);
                }

            }
            if (form_list.Count > 0)
            {
                await _flowInstanceFormRepository.Save(form_list);
            }

        }

        /// <summary>
        /// 保存节点审批人员
        /// </summary>
        /// <param name="instance_id">实例ID</param>
        /// <param name="template_id">模板ID</param>
        /// <param name="biz_order_id">业务ID</param>
        /// <param name="start_user">发起人</param>
        /// <returns></returns>
        public async Task SaveInstanceEmp(int instance_id, int template_id, string biz_order_id, int start_user, Dictionary<string, string> dic = null)
        {
            var node_list = await _flowNodeRepository.GetNodes(template_id, 2);
            var depart_id = await _flowInstanceFormRepository.GetValueByKey(instance_id, "dingding_depart_id");

            //对于每个节点，获取审批人
            var user_list = new List<jj_flow_instance_emp>();
            foreach (var node in node_list)
            {
                var users = await GetApprovers(instance_id, template_id, biz_order_id, node, start_user, depart_id, dic); //获取审批人
                if (users == null || users.Count == 0)
                {
                    throw new BusinessException("未找到业务节点审批人员信息！");
                }

                await this.CheckUserStatusAsync(node, users);

                foreach (var user in users)
                {
                    var model = new jj_flow_instance_emp
                    {
                        instance_id = instance_id,
                        template_id = template_id,
                        node_id = node.id,
                        user_id = user
                    };
                    user_list.Add(model);
                }
            }

            if (user_list == null || user_list.Count == 0)
                throw new BusinessException("未找到业务节点配置人员信息！");

            var template = await _flowTemplateRepository.GetById(template_id);
            if (template == null) throw new BusinessException("审批失败，审批模板不存在！");

            if (template.is_submit_user_check == 0)
            {
                //审批人去重
                var approver = user_list.Select(a => a.user_id).Distinct().ToList();
                if (approver.Count == 1 && approver.FirstOrDefault() == start_user)
                {
                    throw new BusinessException("无法提交，提交人与所有审批人不能是同一个！");
                }
            }

            //保存信息
            await _flowInstanceEmpRepository.Save(user_list);
        }

        public async Task<List<string>> GetUserBizOrderId(string modular_key, int user_id)
        {
            var instance_ids = await _flowInstanceEmpRepository.GetUserBizOrderId(modular_key, user_id);
            return instance_ids;
        }

        /// <summary>
        /// 首页-待办 汇总页
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PageListSearchResultVM<MyTodoListOverview>> GetMyTodoListOverview(int currentUserId, SearchConditionBaseInput input)
        {
            return await _flowInstanceEmpRepository.GetTodoListForCurrentUser(currentUserId, input);

        }

        public async Task<int> GetMyTodoListCount(int currentUserId)
        {
            return await _flowInstanceEmpRepository.GetMyTodoListCount(currentUserId);
        }
        /// <summary>
        /// 首页-待办 详情页
        /// </summary>
        /// <param name="currentUserId"></param>
        /// <returns></returns>
        public async Task<PageListSearchResultVM<MyTodoListDetail>> GetTodoListDetailForCurrentUser(int currentUserId, GetToDoListDetailByTab input)
        {
            return await _flowInstanceEmpRepository.GetTodoListDetailForCurrentUser(currentUserId, input);
        }

        public async Task<IReadOnlyList<SearchByUrlResponse>> SearchByUrl(string url)
        {
            return await _flowInstanceEmpRepository.SearchByUrl(url);
        }

        public async Task<List<JjFlowInstanceVM>> GetInstanceList(string modular_key, string biz_order_id)
        {
            var jjFlowInstances = await _flowInstanceRepository.GetInstanceList(modular_key, biz_order_id);
            var jjFlowInstanceVms = _mapper.Map<List<JjFlowInstanceVM>>(jjFlowInstances);
            return jjFlowInstanceVms;
        }

        public async Task<List<string>> GetUserProcessedBizOrderId(string system_key, string big_modular_key, string modular_key, int user_id)
        {
            return await _flowInstanceRepository.GetUserProcessedBizOrderId(system_key, big_modular_key, modular_key, user_id);
        }

        public async Task<List<string>> GetUserCreateApplyBizOrderId(string system_key, string big_modular_key, string modular_key, int user_id)
        {
            return await _flowInstanceRepository.GetUserCreateApplyBizOrderId(system_key, big_modular_key, modular_key, user_id);
        }

        public async Task<PageListSearchResultVM<JJInstanceViewModel>> GetInstancePageList(JJInstanceSearchCondition searchCondition, int user_id)
        {
            return await _flowInstanceRepository.GetInstancePageList(searchCondition, user_id);
        }

        /// <summary>
        /// 返回用户id 列表
        /// </summary>
        /// <param name="instance_id">实例ID</param>
        /// <param name="template_id">模板ID</param>
        /// <param name="biz_order_id">业务ID</param>
        /// <param name="node">节点信息</param>
        /// <param name="start_user">发起人</param>
        /// <param name="depart_id">部门ID</param>
        /// <returns></returns>
        private async Task<List<int>> GetApprovers(int instance_id, int template_id, string biz_order_id, jj_node node, int start_user, string depart_id, Dictionary<string, string> dic = null)
        {
            var user_ids = new List<int>();
            switch (node.power_type)
            {
                case 1:
                    //【指定审批人】
                    user_ids = await _flowNodeEmpRepository.GetUserIdByNodeId(template_id, node.id);
                    break;
                case 2:
                    //【指定角色】
                    var user_role_code = await _flowNodeEmpRepository.GetRoleCodeByNodeId(template_id, node.id);
                    user_ids = await _erpaUserRoleRepository.GetUserIdsByUserRoleCode(user_role_code);
                    user_ids = user_ids.Distinct().ToList();
                    break;
                case 3:
                    //【组织架构】
                    var approvePlatform = _platformConfig.ApprovePlatform;

                    if (string.IsNullOrWhiteSpace(approvePlatform))
                    {
                        // 如果没有配置默认取钉钉
                        approvePlatform = "DingDing";
                    }

                    user_ids = approvePlatform switch
                    {
                        "DingDing" =>
                            //启用钉钉
                            await GetDingdingLevelApproversAsync(node, biz_order_id, start_user, depart_id, dic),
                        "FeiShu" =>
                            //启用飞书飞书审批
                            await GetFeiShuLevelApproversAsync(node, biz_order_id, start_user, depart_id, dic),
                        _ => throw new NotImplementedException("暂不支持目标平台")
                    };

                    break;
                case 4:
                    //【指定方法】
                    if (!string.IsNullOrWhiteSpace(node.class_name))
                    {
                        user_ids = await GetDingdingUserIds(biz_order_id, node.class_name, start_user, depart_id, dic);
                    }

                    break;
                case 5:
                    //【指定接口】
                    if (!string.IsNullOrWhiteSpace(node.class_name))
                    {
                        user_ids = await _jJFlowTemplateRemoteInterfaceService.GetRemoteInterfaceAsync<jj_node, List<int>>(new RemoteInterfaceInput<jj_node>
                        {
                            biz_order_id = biz_order_id,
                            depart_id = depart_id,
                            start_user = start_user,
                            FunctionCode = node.class_name,
                            Content = node,
                        });
                    }
                    break;
            }

            return user_ids;
        }
        
        /// <summary>
        /// 返回钉钉对应组织架构审批人员
        /// </summary>
        private async Task<List<int>> GetDingdingLevelApproversAsync(jj_node node, string bizOrderId, int startUser, string departId, Dictionary<string, string> dic = null)
        {
            string functionName = node.power_org_level switch
            {
                1 => nameof(Dingding1stLevelApprovers),
                2 => nameof(Dingding2ndLevelApprovers),
                3 => nameof(Dingding3ndLevelApprovers),
                _ => string.Empty
            };

            return await GetDingdingUserIds(bizOrderId, functionName, startUser, departId, dic);
        }
        
        /// <summary>
        /// 返回飞书对应组织架构审批人员
        /// </summary>
        private async Task<List<int>> GetFeiShuLevelApproversAsync(jj_node node, string bizOrderId, int startUser, string departId, Dictionary<string, string> dic = null)
        {
            string functionName = node.power_org_level switch
            {
                1 => nameof(Feishu1StLevelApprovers),
                2 => nameof(Feishu2NdLevelApprovers),
                3 => nameof(Feishu3NdLevelApprovers),
                _ => string.Empty
            };

            return await GetDingdingUserIds(bizOrderId, functionName, startUser, departId, dic);
        }

        /// <summary>
        /// 本地反射获取当前节点审批人钉钉Id
        /// </summary>
        /// <param name="biz_order_id"></param>
        /// <param name="class_name"></param>
        /// <param name="start_user"></param>
        /// <param name="depart_id"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private async Task<List<int>> GetDingdingUserIds(string biz_order_id, string class_name, int start_user, string depart_id, Dictionary<string, string> dic = null)
        {
            //【根据具体类别获取审批人，包括钉钉组织架构、业务系统等】
            var resolveResult = _componentContext.TryResolveNamed(class_name, typeof(IJJApprovers), out var service);
            if (resolveResult)
            {
                var orderService = (IJJApprovers)service;
                return await orderService.GetInstanceNodeEmpInfo(biz_order_id, start_user, depart_id, dic);
            }

            throw new NotImplementedException($"找不到[{class_name}]对应的类型!");
        }

        /// <summary>
        /// 校验审批节点用户状态
        /// </summary>
        /// <param name="node"></param>
        /// <param name="userIds"></param>
        private async Task CheckUserStatusAsync(jj_node node, List<int> userIds)
        {
            var userDatas = await this._erpaUserRepository.GetListAsync(o => userIds.Contains(o.id));

            var templateData = await this._flowTemplateRepository.GetById(node.template_id);

            var updateTemplateUser = await this._erpaUserRepository.GetById(templateData.update_user_id);

            //禁用的用户列表
            var disabledUserDatas = userDatas.Where(o => o.action_flag == 0).ToList();

            switch (node.emp_type)
            {
                //或签
                case 0:
                    if (disabledUserDatas.Count() >= userDatas.Count())
                    {
                        throw new BusinessException($"您发起的流程中有审批人（{string.Join(',', disabledUserDatas.Select(o => o.user_name))}）不存在，请联系【{updateTemplateUser.user_name}】！");
                    }
                    break;
                //会签
                case 1:
                    if (disabledUserDatas.Any())
                    {
                        throw new BusinessException($"您发起的流程中有审批人（{string.Join(',', disabledUserDatas.Select(o => o.user_name))}）不存在，请联系【{updateTemplateUser.user_name}】！");
                    }
                    break;
                default:
                    break;
            }
        }
    }
}